﻿#pragma once

#include <QString>
#include <QVector>
#include <QWidget>
#include <QDialog>
#include <QMessageBox>
#include <QCoreApplication>
#include <QBuffer>
#include <QCloseEvent>
#include <QDataStream>
#include <QDir>
#include <QDateTime>
#include <QPainter>
#include <QDebug>
#include <QWheelEvent>
#include <QMenu>
#include <QFileDialog>
#include <QJsonObject> 
#include <QJsonArray> 
#include <QJsonDocument> 
#include <QJsonValue>
#include <QJsonParseError>
#include <QThreadPool>
#include <QReadWriteLock>
#include <QSharedPointer>
#include <QDir>
#include <qatomic.h>
#include <qatomic.h>
#include <QQueue>
#include <QMutex>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QHostInfo>
#include <QSharedMemory>
#include <QTimer>
#include <QSettings>

#include "opencv2/opencv.hpp"
//using namespace cv;

#include "DeepLearning.h"
#include "kafka.h"
#include "kafka_producer.h"
#include "ConfigUtils.h"


#define  KAFKA_IP "43.137.4.113:9092"

#define suffix_1 "_intermediate"
#define suffix_2 "_result"

#ifdef _WIN32
#pragma execution_character_set("utf-8")
#pragma warning(disable : 4091)
#endif

extern QString		g_strSaveImageDir;			// 存储图片的路径 
extern QString		g_strReleaseImageDir;		// 存储图片的路径 
	
extern QList<QString> g_Whitelist;				// 白名单列表

typedef struct _tagImageData
{
public:
	QImage		image;
	int			nDispId = 0;
	QString		strName;		// 检测名
	QString		strTopicName;	// 主题名

	QString		strStationName; // 站名称
	QString		strStationId;	// 站ID
	QString		strCameraName;	// 相机名称
	QString		strCameraId;	// 相机ID

	QString		strPictureName;	// 图片名称
	QString		strUrl;			// 组装后的下载URL

	QString		strDeviceSN;	// 视频推理机设备 SN

}IMG_DATA;


static float  getWH_Rate(int w, int h)
{
	if (w == 0 || h == 0)
	{
		return 1;
	}

	if (w > h)
	{
		return w / h;
	}
	if (w < h)
	{
		return h / w;
	}
	return 1;
}



static bool DirExistEx(QString fullPath)
{
	QFileInfo info(fullPath);
	QString str = info.absolutePath();

	QDir dir(str);
	if (dir.exists())
	{
		return true;
	}
	else
	{
		//不存在当前目录，创建，可创建多级目录
		bool ok = dir.mkpath(str);
		return ok;
	}
}


static cv::Mat QImage2cvMat(const QImage& image)
{
	cv::Mat mat;
	switch (image.format())
	{
	case QImage::Format_Grayscale8: // 灰度图，每个像素点1个字节（8位）
		// Mat构造：行数，列数，存储结构，数据，step每行多少字节
		mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
		break;
	case QImage::Format_ARGB32: // uint32存储0xAARRGGBB，pc一般小端存储低位在前，所以字节顺序就成了BGRA
	case QImage::Format_RGB32: // Alpha为FF
	case QImage::Format_ARGB32_Premultiplied:
		mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
		break;
	case QImage::Format_RGB888: // RR,GG,BB字节顺序存储
		mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
		// opencv需要转为BGR的字节顺序
		cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);
		break;
	case QImage::Format_RGBA64: // uint64存储，顺序和Format_ARGB32相反，RGBA
		mat = cv::Mat(image.height(), image.width(), CV_16UC4, (void*)image.constBits(), image.bytesPerLine());
		// opencv需要转为BGRA的字节顺序
		cv::cvtColor(mat, mat, cv::COLOR_RGBA2BGRA);
		break;
	}
	return mat;
}


//矩形中心点
static cv::Point getCenterPoint(cv::Rect rect)
{
	cv::Point cpt;
	cpt.x = rect.x + cvRound(rect.width / 2.0);
	cpt.y = rect.y + cvRound(rect.height / 2.0);
	return cpt;
};

// 标签坐标信息
typedef struct _Target_rect
{
	_Target_rect()
	{
		height = 0;
		width = 0;
		x = 0;
		y = 0;
	}
public:
	int			height;	// 标签宽
	int			width;	// 标签高
	int			x;		// 标签 x
	int			y;		// 标签 y
};


// 检测到的标签信息
typedef struct _Target_info
{
	_Target_info()
	{
		target_id = 0;
		quality_score = 0;
	}
public:
	QString						target_type;	// 标签名称
	int							target_id;		// 标签 id
	float						quality_score;	// 标签 评分
	_Target_rect				target_rect;	// 标签 区域
};


// 检测的具体信息
typedef struct _Event_info
{
public:
	QString						event_type;			// 检测的具体项目（主题名称）
	QVector <_Target_info>		target_info;		// 检测的标签信息
};


// 检测结果
typedef struct _Detect_list
{
	_Detect_list()
	{
		detect_picture = "oss srever";
	}
public:

	QString					detect_picture;		// 抓拍图片上传OSS，内容为文件名
	_Event_info				event_info;		// 检测的具体信息
};


// 检测 事件
typedef struct _R_data
{
	_R_data()
	{
		channel_number = 0;
		daeect_time = QDateTime::currentDateTime().toTime_t();
	}
public:

	QString					station_id;			// 站号
	QString					station_name;		// 站名
	int						channel_number;		// 相机序号
	QString					channel_name;		// 相机名称
	QString					picture_name;		// 图片名称
	int						daeect_time;		// 检测时间戳

	QVector<_Detect_list>	detect_list;		// 事件列表

};



// 算法的基础信息
typedef struct _R_basic
{
	_R_basic()
	{
		code = 0;
		ver = "1.0.0.1";
		time = QDateTime::currentDateTime().toTime_t();
		msg = "success";
		server_name = "ai saever";
		server_url = "192.168.1.100:888";
	}
public:
	int					code;			// 状态码：0-成功，1-失败
	QString				server_name;	// 算法服务器的名称
	QString				server_url;		// 算法服务器的 IP:Port
	QString				msg;			// 检测结果 （success or error msg）
	QString				ver;			// 算法的版本号
	int					time;			// 检测的时间戳
};



// 算法返回结果
typedef struct _tagResults
{
public:
	_R_basic		_base;		// 算法基础信息
	_R_data			_data;		// 算法数据
	
	QString			strTopicName;

public:
	QString toJSon()
	{
		QJsonObject rootObj;
		{
			QJsonObject baseObj;
			baseObj.insert("code", _base.code);
			baseObj.insert("server_name", _base.server_name);
			baseObj.insert("server_url", _base.server_url);
			baseObj.insert("time", _base.time);
			baseObj.insert("msg", _base.msg);
			baseObj.insert("ver", _base.ver);
			rootObj.insert("basic", baseObj);
		}

		{
			QJsonObject dataObj;

			{
				QJsonObject event_detect;
				event_detect.insert("station_id", _data.station_id);
				event_detect.insert("station_name", _data.station_name);
				event_detect.insert("channel_number", _data.channel_number);
				event_detect.insert("channel_name", _data.channel_name);
				event_detect.insert("picture_name", _data.picture_name);

				QJsonArray detect_list;
				for (int i = 0; i < _data.detect_list.size(); i++)
				{
					_Detect_list det = _data.detect_list[i];

					QJsonObject detect_;
					detect_.insert("detect_picture", det.detect_picture);

					QJsonObject event_info;
					event_info.insert("event_type", det.event_info.event_type);
				
					QJsonArray target_list;
					for (int j = 0; j < det.event_info.target_info.size(); j++)
					{
						_Target_info info = det.event_info.target_info[j];

						QJsonObject target_;
						target_.insert("target_type", info.target_type);
						target_.insert("target_id", info.target_id);
						target_.insert("quality_score", info.quality_score);

						QJsonObject target_rect;
						target_rect.insert("height", info.target_rect.height);
						target_rect.insert("width", info.target_rect.width);
						target_rect.insert("x", info.target_rect.x);
						target_rect.insert("y", info.target_rect.y);

						target_.insert("target_rect", target_rect);

						target_list.push_back(target_);
					}
					event_info.insert("target_info", target_list);


					detect_.insert("event_info", event_info);

					detect_list.push_back(detect_);
				}
				event_detect.insert("detect_list", detect_list);

				dataObj.insert("event_detect", event_detect);
			}
			rootObj.insert("data", dataObj);
		}


		QString strTime = QDateTime::currentDateTime().toString("MM-dd_hh-mm-ss");

		QJsonDocument document = QJsonDocument(rootObj);
		QString str = QString(document.toJson());

		QJsonParseError jsonError;
		QJsonDocument doc = QJsonDocument::fromJson(str.toUtf8(), &jsonError);
		// 判断是否解析失败
		if (jsonError.error != QJsonParseError::NoError && !doc.isNull())
		{
			QString strPath = "E://Json//" + strTopicName + "//" + _data.station_name + "//" + strTime + ".json";
			DirExistEx(strPath);
			QFile file(strPath);
			if (file.open(QIODevice::ReadWrite))
			{
				file.write(str.toUtf8());
			}
			file.close();
			return "error";
		}

		

		return str;
	}

	void pushToOSS(QString strUrl)
	{

	}

	void setImageData(IMG_DATA img_data)
	{
		_data.station_name = img_data.strStationName;
		_data.station_id = img_data.strStationId;
		_data.channel_name = img_data.strCameraName;
		_data.channel_number = img_data.strCameraId.toInt();
		_data.picture_name = img_data.strUrl;	

		strTopicName = img_data.strTopicName;
	}


	void setResults(QString strPicName, std::vector<DetectResult> results, int offset_x = 0, int offset_y = 0)
	{
		_Detect_list detect;
		detect.detect_picture = "OSS server IP";

		detect.event_info.event_type = strTopicName;
		
		for (int i = 0; i < results.size(); i++)
		{
			DetectResult res = results[i];

			_Target_info target;
			target.target_type = strPicName;
			target.target_id = i + 1 ;
			target.quality_score = res.score;
			target.target_rect.width = res.box.width;
			target.target_rect.height = res.box.height;
			target.target_rect.x = res.box.x + offset_x;
			target.target_rect.y = res.box.y + offset_y;
			

			detect.event_info.target_info.push_back(target);
		}
		_data.detect_list.push_back(detect);

	}


	/// <summary>
	/// 设置算法版本号（算法的发布日期）
	/// </summary>
	/// <param name="strVersion"></param>
	void setVersion(QString strVersion)
	{
		if (!strVersion.isEmpty())
		{
			QFileInfo info(strVersion);
			_base.ver = info.fileName();
		}

	}

};

/*

{
  "basic":{
	"code":0,
	"server_name":"",
	"server_url":"47.100.83.110:8001",
	"msg": "success",
	"time": 1731012432,
	"ver": "1.0.1"
  },
  "data":{
	"event_detect":{
	  "station_id": "680007",
	  "station_name": "马鞍山长江钢铁换电站",
	  "channel_number": 2,
	  "channel_name": "出口",
	  "picture_name": "1.jpg",
	  "detect_list":[
		{
		 "detect_pic":"detect1.jpg",
		  "event_info":{
			"event_type":"battery_shell_broken",
			"target_info":[
			  { 
				"target_type":"broken_shell",
				"target_id":1,
				"quality_score":0.92,
				"target_rect":{
				  "height": 102,
				  "width": 67,
				  "x": 32,
				  "y": 189
				},
				"target_type":"broken_shell",
				"target_id":2,
				"quality_score":0.67,
				"target_rect":{
				  "height": 12,
				  "width": 54,
				  "x": 12,
				  "y": 85
				}
			]
		  }
		},
		{
		  ......
		}
	  ]
	}
	"detect_time": 1731053187
  }
}



*/